package com.gitee.magic.framework.base.rest;

import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.util.Map;

import com.gitee.magic.core.exception.ApplicationException;
import com.gitee.magic.core.utils.StringUtils;

/**
 * @author start
 */
public class HttpMultipartForm {

	private static final String MULTIPART_FROM_DATA = "multipart/form-data";
	private static final String PREFIX = "--";
	private static final String LINEND = "\r\n";
	
	/**
	 * 表单FormData文件上传
	 * @param conn
	 * @param formParams
	 * @param multipartParams
	 */
	public static void multipartFormData(HttpURLConnection conn,Map<String,String> formParams,Map<String,MultipartForm> multipartParams) {
		String boundary=StringUtils.random();
		conn.setRequestProperty("Content-Type", MULTIPART_FROM_DATA+ ";boundary=" + boundary);  
		try(DataOutputStream out = new DataOutputStream(conn.getOutputStream())){
			requestFormData(boundary,out,formParams);
			requestFormInputStream(boundary,out,multipartParams);
			requestFormEnd(boundary,out);
			out.flush();
		} catch (IOException e) {
			throw new ApplicationException(e);
		}
	}
	
	/**
	 * 生成Form表单数据体
	 * 
	 * @param formDatas
	 * @return
	 */
	private static void requestFormData(String boundary,DataOutputStream out,Map<String, String> formDatas) {
		StringBuilder content = new StringBuilder();
		for (Map.Entry<String, String> entry : formDatas.entrySet()) {
			content.append(PREFIX);
			content.append(boundary);
			content.append(LINEND);
			content.append("Content-Disposition: form-data; name=\"" + entry.getKey() + "\"" + LINEND);
			content.append(LINEND);
			content.append(entry.getValue());
			content.append(LINEND);
		}
		try {
			out.write(content.toString().getBytes());
		} catch (IOException e) {
			throw new ApplicationException(e);
		}
	}
	
	/**
	 * 生成Form表单文件上传流,文件上传需设置请求内容类型 
	 * conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
	 */
	private static void requestFormInputStream(String boundary,DataOutputStream out, Map<String, MultipartForm> multipartParams) {
		for (Map.Entry<String, MultipartForm> multipart : multipartParams.entrySet()) {
			MultipartForm part=multipart.getValue();
			StringBuilder content = new StringBuilder();
			content.append(PREFIX);
			content.append(boundary);
			content.append(LINEND);
			content.append("Content-Disposition: form-data; name=\""+part.getContentName()+"\"; filename=\"" + multipart.getKey() + "\"" + LINEND);
			content.append("Content-Type: "+part.getContentType()+ LINEND);
			content.append(LINEND);
			try {
				out.write(content.toString().getBytes());
			} catch (IOException e) {
				throw new ApplicationException(e);
			}
			int len = 0;
			byte[] buffer = new byte[1024];
			try(InputStream is = part.getInputStream()) {
				while ((len = is.read(buffer)) != -1) {
					out.write(buffer, 0, len);
				}
			} catch (IOException e) {
				throw new ApplicationException(e);
			}
			try {
				out.write(LINEND.getBytes());
			} catch (IOException e) {
				throw new ApplicationException(e);
			}
		}
	}
	
	/**
	 * 请求结束标志
	 * @param boundary
	 * @param out
	 */
	private static void requestFormEnd(String boundary,DataOutputStream out) {
		try {
			out.write((PREFIX + boundary + PREFIX + LINEND).getBytes());
		} catch (IOException e) {
			throw new ApplicationException(e);
		}
	}
	
	
	/**
	 * 获取文件上传流接口
	 * @author start
	 *
	 */
	public interface MultipartForm{
		
		default String getContentName() {
			return "file";
		}

		/**
		 * 输入流
		 * @return
		 */
		InputStream getInputStream();

		/**
		 * 数据内容类型
		 * @return
		 */
		default String getContentType() {
			return "application/octet-stream";
		}
		
	}
	
}
